package com.quanyan.place.wrapper.impl;

import static com.quanyan.place.constants.PlaceConstants.UNIT_TYPE_BASE;
import static com.quanyan.place.constants.PlaceConstants.UNIT_TYPE_COMBINE;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;

import com.quanyan.common.mail.EmailUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import com.quanyan.common.constants.Constants;
import com.quanyan.common.enums.SysParameterConfigEnum;
import com.quanyan.common.utils.CommonUtils;
import com.quanyan.common.utils.DateTimeUtils;
import com.quanyan.common.utils.StringUtil;
import com.quanyan.place.constants.PlaceConstants;
import com.quanyan.place.entity.TbBizPlace;
import com.quanyan.place.entity.TbBizPlaceBuyContractDetail;
import com.quanyan.place.entity.TbBizPlaceBuyContractDetailExample;
import com.quanyan.place.entity.TbBizPlaceCategory;
import com.quanyan.place.entity.TbBizPlaceUnit;
import com.quanyan.place.entity.TbBizPlaceUnitCombine;
import com.quanyan.place.entity.TbBizPlaceUnitCombineExample;
import com.quanyan.place.entity.TbBizPlaceUnitExample;
import com.quanyan.place.entity.TbBizPlaceUnitSalePlan;
import com.quanyan.place.entity.TbBizPlaceUnitSalePlanMain;
import com.quanyan.place.entity.TbBizPlaceUnitTime;
import com.quanyan.place.entity.TbCommonParameter;
import com.quanyan.place.entity.apiresp.RespPlaceInfo;
import com.quanyan.place.entity.vo.PlaceCategoryVo;
import com.quanyan.place.entity.vo.PlaceUnitSalePlan;
import com.quanyan.place.entity.vo.PlaceUnitTime;
import com.quanyan.place.mapper.TbBizPlaceUnitCombineMapper;
import com.quanyan.place.service.BaseService;
import com.quanyan.place.service.PlaceBaseService;
import com.quanyan.place.service.PlaceInnerService;
import com.quanyan.place.utils.PlaceUtil;
import com.quanyan.place.wrapper.PlaceUnitSalePlanWrapper;


/**
 * 场馆销售计划wrapper
 * Created by yangyun on 16-6-6.
 */
@Service("placeUnitSalePlanWrapper")
public class PlaceUnitSalePlanWrapperImpl implements PlaceUnitSalePlanWrapper {

    @Autowired
    PlaceInnerService placeInnerService;

    @Autowired
    PlaceBaseService placeBaseService;

    @Autowired
    BaseService baseService;

    @Autowired
    TbBizPlaceUnitCombineMapper placeUnitCombineMapper;

    @Value("${place.mail.switch}")
    private String switchFlg;

    private final static String placeAdminUser = "yun.yang@quncaotech.com";


    private Logger logger = LoggerFactory.getLogger(PlaceUnitSalePlanWrapperImpl.class);

    /**
     * 根据场馆Id和类目ID获取场地可销售列表，用于定价
     * @param placeId
     * @param categoryId
     * @return
     */
    public List<PlaceUnitSalePlan> getPlaceUnitSalePlan(Integer placeId, Byte categoryId) {
        List<PlaceUnitSalePlan> result = new ArrayList<PlaceUnitSalePlan>();
        // 获取场馆下已签约场地列表
        List<TbBizPlaceUnit> placeUnitList = placeBaseService.getPlaceUnitByPlaceId(placeId, categoryId, true);
        if (null == placeUnitList || placeUnitList.size() == 0) {
            return result;
        }
        // 如果存在销售计划 从销售计划表查询
        List<PlaceUnitSalePlan> placeUnitSalePlanList = placeInnerService.getPlaceSalePlanFromDB(placeId, categoryId, UNIT_TYPE_BASE);

        TbBizPlaceCategory placeCategory = placeBaseService.getPlaceCategory(placeId, Integer.valueOf(categoryId));
        int intervalTime = PlaceUtil.getTimeInterval(placeCategory.getMinSaleTimeUnit());
        // 查询所有已定价和未定价场地信息
        List<PlaceUnitSalePlan> allUnitSalePlanList = this.getAllUnitSalePlanList(placeId, placeUnitList, intervalTime);
        if (null != placeUnitSalePlanList && placeUnitSalePlanList.size() > 0){
            List<PlaceUnitSalePlan> subTractList = (List<PlaceUnitSalePlan>) CollectionUtils.subtract(allUnitSalePlanList, placeUnitSalePlanList);
            // 已经定价的销售计划 uniton 从未定价（比如刚刚签约的场地）的销售计划
            result = (List<PlaceUnitSalePlan>) CollectionUtils.union(placeUnitSalePlanList, subTractList);
            return result;
        }  else {
            return allUnitSalePlanList;
        }
    }

    /**
     * 根据数据库查询的销售计划模板封装销售数据
     * @param placeId
     * @return
     */
    public List<PlaceUnitSalePlan> getPlaceUnitSalePlan(Integer placeId) {
        List<PlaceUnitSalePlan> salePlansResult = new ArrayList<PlaceUnitSalePlan>();
        List<TbBizPlaceUnitSalePlanMain> salePlanList = placeInnerService.getPlaceSalePlanTemplate(placeId, null, null, UNIT_TYPE_BASE);
        for (TbBizPlaceUnitSalePlanMain oracSalePlan : salePlanList){
            PlaceUnitSalePlan salePlan = new PlaceUnitSalePlan();
            salePlan.setPlaceId(placeId);
            salePlan.setId(oracSalePlan.getId());
            salePlan.setPlaceUnitId(oracSalePlan.getPlaceUnitId());
            salePlan.setPlaceUnitName(oracSalePlan.getPlaceUnitName());
            salePlan.setTimeType(oracSalePlan.getTimeType());
            salePlan.setStartTime(DateTimeUtils.convertDate2String("HH:mm:ss", oracSalePlan.getStartTime()));
            salePlan.setEndTime(DateTimeUtils.convertDate2String("HH:mm:ss", oracSalePlan.getEndTime()));
            salePlan.setPrice(oracSalePlan.getPrice());
            salePlan.setMemberPrice(oracSalePlan.getMemberPrice());
            salePlan.setStatus(oracSalePlan.getStatus()); // 已定价
            salePlansResult.add(salePlan);
        }
        return salePlansResult;
    }

    /**
     * 根据营业时间和签约状况组合可销售计划列表
     * @param placeId
     * @param placeUnitList
     * @return
     */
    public List<PlaceUnitSalePlan> getAllUnitSalePlanList(Integer placeId, List<TbBizPlaceUnit> placeUnitList, int timeInterval) {

        List <PlaceUnitSalePlan> result = new ArrayList<PlaceUnitSalePlan>();
        // 获取营业时间 （按场地Id分组）
        Map<Integer,List<PlaceUnitTime>> unitTimeMap = getSplitPlaceUnitTimeByUnitId(placeId, timeInterval);
        // 根据场馆ID获取合同明细 key:placeUnitId
        Map<Integer,List<TbBizPlaceBuyContractDetail>> contractDetailMap = this.getPlaceContractDetailGroupByUnitId(placeId);
        // 签约状况
        for (TbBizPlaceUnit bizPlaceUnit : placeUnitList) {
            List<PlaceUnitSalePlan> unitSalePlans = new ArrayList<PlaceUnitSalePlan>();
            if (contractDetailMap.containsKey(bizPlaceUnit.getId())) {
                List<TbBizPlaceBuyContractDetail> contractDetailList = contractDetailMap.get(bizPlaceUnit.getId());
                for (TbBizPlaceBuyContractDetail detail : contractDetailList) {
                    if (PlaceConstants.BUY_TYPE_WHOLE.equals(detail.getBuyType()) || PlaceConstants.BUY_TYPE_GROUP.equals(detail.getBuyType())) {
                        // 整馆和包片购买方式  按营业时间返回销售计划
                        if (unitTimeMap != null && unitTimeMap.containsKey(bizPlaceUnit.getId())) {
                            unitSalePlans = organizeSalePlan(unitTimeMap.get(bizPlaceUnit.getId()), bizPlaceUnit);
                        } else {
                            logger.warn(bizPlaceUnit.getName() + "场地没有维护营业时间");
                        }
                        break;
                    }
                    if (PlaceConstants.BUY_TYPE_TIME.equals(detail.getBuyType()) ||
                            PlaceConstants.BUY_TYPE_TRUE_TIME.equals(detail.getBuyType()) ||
                            PlaceConstants.BUY_TYPE_FALSE_TIME.equals(detail.getBuyType()) ) {
                        // 时段买入方式 只有签约时段作为可销售计划
                        PlaceUnitSalePlan placeUnitSalePlan = new PlaceUnitSalePlan();
                        placeUnitSalePlan.setStartTime(DateTimeUtils.convertDate2String("HH:mm:ss", detail.getBuyStartTime()));
                        placeUnitSalePlan.setEndTime(DateTimeUtils.convertDate2String("HH:mm:ss", detail.getBuyEndTime()));
                        placeUnitSalePlan.setTimeType(detail.getDateRange());
                        placeUnitSalePlan.setPlaceUnitId(bizPlaceUnit.getId());
                        placeUnitSalePlan.setPlaceUnitName(bizPlaceUnit.getName());
                        placeUnitSalePlan.setPlaceId(bizPlaceUnit.getPlaceId());
                        placeUnitSalePlan.setStatus(Constants.BYTE_ZERO); // 未定价
                        unitSalePlans.add(placeUnitSalePlan);
                    }
                }
            }
            result.addAll(unitSalePlans);
        }
        return result;
    }

    /**
     * 根据场馆ID获取合同明细（按场地Id分组）
     * @param placeId
     * @return
     */
    public Map<Integer,List<TbBizPlaceBuyContractDetail>> getPlaceContractDetailGroupByUnitId(Integer placeId) {
        Map<Integer,List<TbBizPlaceBuyContractDetail>> resultMap = new HashMap<Integer,List<TbBizPlaceBuyContractDetail>>();
        TbBizPlaceBuyContractDetailExample example = new TbBizPlaceBuyContractDetailExample();
        TbBizPlaceBuyContractDetailExample.Criteria criteria = example.createCriteria();
        criteria.andPlaceIdEqualTo(placeId);
        criteria.andFinishDateGreaterThan(new Date()); // TODO
        //List<TbBizPlaceBuyContractDetail> tbBizPlaceBuyContractDetailList = placeBuyContractDetailMapper.selectByExample(example);
         // 查询场馆合同
        List<TbBizPlaceBuyContractDetail> tbBizPlaceBuyContractDetailList = placeInnerService.getPlaceContractDetail(placeId, true);
        List<TbBizPlaceBuyContractDetail> contractDetailList = null;
        for (TbBizPlaceBuyContractDetail detail : tbBizPlaceBuyContractDetailList){
            if (resultMap.containsKey(detail.getPlaceUnitId())){
                contractDetailList = resultMap.get(detail.getPlaceUnitId());
            } else {
                contractDetailList = new ArrayList<TbBizPlaceBuyContractDetail>();
            }
            contractDetailList.add(detail);
            resultMap.put(detail.getPlaceUnitId(),contractDetailList);
        }
        return resultMap;
    }

    /**
     * 根据场馆获取营业时段（按场地Id分组）
     * @param placeId
     * @param section
     * @return
     */
    private Map<Integer,List<PlaceUnitTime>> getSplitPlaceUnitTimeByUnitId(Integer placeId, Integer section) {
        Map<Integer,List<PlaceUnitTime>> result = new HashMap<Integer,List<PlaceUnitTime>>();
        List<PlaceUnitTime> placeUnitTimeList = null;
        List<TbBizPlaceUnitTime> placeUnitPrimeTimeList = placeInnerService.getPlaceUnitTimeList(placeId);
        if (!placeUnitPrimeTimeList.isEmpty()) {
            for (TbBizPlaceUnitTime placeUnitTime : placeUnitPrimeTimeList) {
                String start = placeUnitTime.getStartTime();
                String end = placeUnitTime.getEndTime();
                List<String> timeList = DateTimeUtils.getIntervalTimeList(start, end, section);
                if (result.containsKey(placeUnitTime.getPlaceUnitId())){
                    placeUnitTimeList = result.get(placeUnitTime.getPlaceUnitId());
                } else {
                    placeUnitTimeList = new ArrayList<PlaceUnitTime>();
                }
                if (!timeList.isEmpty()) {
                    PlaceUnitTime unitTime;
                    for (int n = 0; n < timeList.size() - 1; n++){
                        unitTime = new PlaceUnitTime();
                        unitTime.setStartTime(timeList.get(n));
                        unitTime.setEndTime(timeList.get(n + 1));
                        unitTime.setPlaceUnitId(placeUnitTime.getPlaceUnitId());
                        unitTime.setTimeType(placeUnitTime.getTimeType());
                        //0为非黄金时段，1为黄金时段
                        unitTime.setIsPrimeTime(placeUnitTime.getIsPrimeTime());
                        placeUnitTimeList.add(unitTime);
                    }
                    result.put(placeUnitTime.getPlaceUnitId(),placeUnitTimeList);
                }
            }
        }
        return result;
    }

    /**
     * 整馆和包片购入方式按营业时间封装销售计划
     * @param unitTimeList
     * @param bizPlaceUnit
     * @return
     */
    private List<PlaceUnitSalePlan> organizeSalePlan(List<PlaceUnitTime> unitTimeList, TbBizPlaceUnit bizPlaceUnit) {
        List<PlaceUnitSalePlan> unitSalePlans = new ArrayList<PlaceUnitSalePlan>();
        for (PlaceUnitTime unitTime : unitTimeList){
            PlaceUnitSalePlan salePlan = new PlaceUnitSalePlan();
            salePlan.setStartTime(unitTime.getStartTime());
            salePlan.setEndTime(unitTime.getEndTime());
            salePlan.setTimeType(unitTime.getTimeType());
            salePlan.setPlaceUnitId(bizPlaceUnit.getId());
            salePlan.setPlaceUnitName(bizPlaceUnit.getName());
            salePlan.setPlaceId(bizPlaceUnit.getPlaceId());
            salePlan.setStatus(Constants.BYTE_ZERO); // 未定价
            unitSalePlans.add(salePlan);
        }
        return unitSalePlans;
    }

    /**
     * 获取场馆经营运动类型
     * @param placeId
     * @return
     */
    public PlaceCategoryVo getPlaceCategory(Integer placeId) {
        PlaceCategoryVo placeCategoryVo = new PlaceCategoryVo();
        TbBizPlace place = placeBaseService.getPlaceById(placeId);
        List<TbBizPlaceCategory> tbBizPlaceCategoryList = placeBaseService.getPlaceCategoryList(placeId);
        if(tbBizPlaceCategoryList != null && tbBizPlaceCategoryList.size() > 0){
            Set<Integer> placeCategorySet = new HashSet<Integer>();
            for (TbBizPlaceCategory tbBizPlaceCategory : tbBizPlaceCategoryList) {
                placeCategorySet.add(tbBizPlaceCategory.getCategoryId());
            }
            placeCategoryVo.setCategoryIdSet(placeCategorySet);
        }
        placeCategoryVo.setPlaceId(placeId);
        placeCategoryVo.setPlaceName(place.getName());
        return placeCategoryVo;
    }

    @Override
    public List<String> savePlaceSalePlanSingle(PlaceUnitSalePlan placeUnitSalePlan,int period) {
        return placeInnerService.saveSinglePlaceSalePlan(placeUnitSalePlan,period, UNIT_TYPE_BASE); // TODO
    }

    public List<String> savePlaceSalePlanBatch(List<PlaceUnitSalePlan> salePlanList,int period){
        return placeInnerService.savePlaceSalePlanBatch(salePlanList,period, UNIT_TYPE_BASE); // TODO
    }

    /**
     * 场馆销售计划同步（定时同步）
     */
    public void syncPlaceSalePlanScheduled(){
        // 查询销售计划模板
        Calendar calendar = Calendar.getInstance(Locale.CHINA);
        int weekDay = calendar.get(Calendar.DAY_OF_WEEK);

        Map<Integer,Date> dateMap = new HashMap<Integer,Date>();
        List<RespPlaceInfo> placeList = placeInnerService.getCanSalePlace(0, Constants.MAX_PAGE_SIZE);
        TbCommonParameter parameter = baseService.getParameterByKey(SysParameterConfigEnum.CONFIG_PLACE_SALEPLAN_SYNC_PERIOD.getCode());
        int period = PlaceConstants.DEFAULT_PRICE_WEEK_PERIOD;  // 需要同步的周期
        if (parameter != null && parameter.getParameterValue() != null){
            period = Integer.valueOf(parameter.getParameterValue());
        }
        for (int weekIndex=1; weekIndex<=period; weekIndex++){
            Calendar objCalendar = Calendar.getInstance(Locale.CHINA);
            objCalendar.add(Calendar.DAY_OF_WEEK, 7 * weekIndex); // 同步一周后一天的数据
            dateMap.put(weekIndex,objCalendar.getTime());
        }
        //  当前的星期
        if (weekDay > 1){
            weekDay = weekDay - 1;
        } else if (weekDay == 1){
            weekDay = 7;
        }
        Set<Integer> placeSet = new HashSet<Integer>();
        for (RespPlaceInfo place : placeList){
            // 考虑到批量插入时，如果有一条数据销售计划存在其它数据都无法插入  按场馆 周期同步一个个同步
            List<TbBizPlaceUnitSalePlanMain> salePlanModelList = placeInnerService.getPlaceSalePlanTemplate(place.getId(), null, weekDay, null);
            if (null == salePlanModelList || salePlanModelList.size() ==0){
                continue;
            }
            for (int weekIndex=1; weekIndex<=period; weekIndex++){
                int currentSalePlanNum = placeInnerService.countSalePlanNum(place.getId(),dateMap.get(weekIndex));
                if (currentSalePlanNum > 0){
                    if (salePlanModelList.size() == currentSalePlanNum){
                        // 跟模板数据一致
                        continue;
                    } else {
                        placeSet.add(place.getId());
                        logger.error("模板数据和销售计划不一致 placeId:" + place.getId() + "-date:" + dateMap.get(weekIndex));
                        placeInnerService.deleteSalePlanByPlaceAndDate(place.getId(), dateMap.get(weekIndex));
                    }
                }
                syncSalePlanByDate(dateMap.get(weekIndex), place, salePlanModelList);
            }
        }
        if (StringUtils.isNotEmpty(switchFlg) && "1".equals(switchFlg)){
            // 发邮件告警
            placeBaseService.sendTextEmails("销售计划同步告警", "场馆销售计划同步" + placeSet.toString());
        }

    }

    private void syncSalePlanByDate(Date date, RespPlaceInfo place, List<TbBizPlaceUnitSalePlanMain> salePlanModelList) {
        // 先把所有的组合场地的子场信息读取回来
        List<Integer> combineUnitIds = new ArrayList<>();
        for (TbBizPlaceUnitSalePlanMain template : salePlanModelList) {
            if (UNIT_TYPE_COMBINE.equals(template.getUnitType())) {
                combineUnitIds.add(template.getPlaceUnitId());
            }
        }

        Map<Integer, List<Integer>> buId2BaseUnitIds = new HashMap<>();
        if (combineUnitIds.size() > 0) {
            TbBizPlaceUnitCombineExample example = new TbBizPlaceUnitCombineExample();
            TbBizPlaceUnitCombineExample.Criteria criteria = example.createCriteria();
            criteria.andPlaceIdEqualTo(place.getId());
            criteria.andIdIn(combineUnitIds);
            List<TbBizPlaceUnitCombine> cus = placeUnitCombineMapper.selectByExample(example);
            if (cus != null && cus.size() > 0) {
                for (TbBizPlaceUnitCombine cu : cus) {
                    String baseUnits = cu.getBaseUnits();
                    if (baseUnits != null && !baseUnits.isEmpty()) {
                        buId2BaseUnitIds.put(cu.getId(), PlaceUtil.splitIds(baseUnits));
                    }
                }
            }
        }

        List <TbBizPlaceUnitSalePlan> salePlanList = new ArrayList<TbBizPlaceUnitSalePlan>();
        for (TbBizPlaceUnitSalePlanMain template : salePlanModelList){
            // 定时同步只同步当前日期N 周后那天的数据
            TbBizPlaceUnitSalePlan salePlan = new TbBizPlaceUnitSalePlan();
            salePlan.setDate(date);
            salePlan.setSaleId(CommonUtils.createSaleID(template.getPlaceUnitId(), date, template.getStartTime(), template.getEndTime())); // 销售计划Id
            salePlan.setSalePlanMainId(template.getId());
            salePlan.setStatus(PlaceConstants.PLACE_PREORDER_STATUS); // 状态：未预定
            salePlan.setCategoryId(template.getCategoryId());
            salePlan.setTimeType(template.getTimeType());
            salePlan.setPlaceId(template.getPlaceId());
            salePlan.setPlaceUnitId(template.getPlaceUnitId());
            salePlan.setPlaceUnitName(template.getPlaceUnitName());
            salePlan.setPrice(template.getPrice());
            salePlan.setMemberPrice(template.getMemberPrice());
            salePlan.setPlaceId(template.getPlaceId());
            salePlan.setStartTime(template.getStartTime());
            salePlan.setEndTime(template.getEndTime());
            salePlan.setVersion(template.getVersion());
            salePlan.setIsEffective(Constants.BYTE_ONE);
            salePlan.setCreateUid(template.getCreateUid());
            salePlan.setCreateTime(Calendar.getInstance().getTime());
            salePlan.setUpdateUid(template.getUpdateUid());
            salePlan.setUpdateTime(Calendar.getInstance().getTime());
            if (template.getBundleNo() != null){
                if (template.getBundleNo() == 0){
                    salePlan.setBundleNo(0);
                } else {
                    String bundleNo = template.getPlaceUnitId()+""+template.getBundleNo();
                    salePlan.setBundleNo(Integer.valueOf(bundleNo));
                }
            }

            salePlan.setUnitType(template.getUnitType());
            if (UNIT_TYPE_COMBINE.equals(template.getUnitType())) {
                List<Integer> baseUnitIds = buId2BaseUnitIds.get(template.getPlaceUnitId());
                if (baseUnitIds != null && baseUnitIds.size() > 0) {
                    List<String> saleIds = new ArrayList<>();
                    for (Integer buId : baseUnitIds) {
                        saleIds.add(CommonUtils.createSaleID(buId, date, template.getStartTime(), template.getEndTime()));
                    }
                    salePlan.setSubSaleplans(StringUtil.join("|", saleIds));
                } else {
                    // 数据异常!!!
                    logger.error("无法获取组合场地:{}的子场地信息", template.getPlaceUnitId());
                    continue;
                }
            }

            salePlanList.add(salePlan);
        }
        try {
            placeInnerService.insertSalePlanBatch(salePlanList);
        } catch (Exception e) {
            logger.error("销售计划同步失败:placeId：{} 名称:{} 失败:{}", place.getId(), place.getName(), e.getMessage());
        }
    }

    /**
     * 删除已经置为无效的销售计划
     */
    public void delInvalidSalePlan(Integer placeId){
        placeInnerService.delInvalidSalePlan(placeId);
    }

    /**
     * 组合场同步测试
     * @param placeId
     * @param date
     */
    @Override
    public void syncPlaceSalePlan(Integer placeId, Date date) {
        Calendar objCalendar = Calendar.getInstance();
        objCalendar.setTime(date);
        int weekDay = objCalendar.get(Calendar.DAY_OF_WEEK);
        if (weekDay > 1){
            weekDay = weekDay - 1;
        } else if (weekDay == 1){
            weekDay = 7;
        }
        List<TbBizPlaceUnitSalePlanMain> salePlanModelList = placeInnerService.getPlaceSalePlanTemplate(placeId, null, weekDay, null);
        RespPlaceInfo place = new RespPlaceInfo();
        place.setId(placeId);
        place.setName("Test");
        if (placeInnerService.checkSalePlanNum(place.getId(),date, salePlanModelList.size())){
            return;
        } else {
            logger.error("模板数据和销售计划不一致 placeId:", place.getId() + "-date:" + date);
            placeInnerService.deleteSalePlanByPlaceAndDate(place.getId(), date);
        }
        syncSalePlanByDate(date, place, salePlanModelList);
    }

}
